import 'dart:async';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:usb_serial/transaction.dart';
import 'package:usb_serial/usb_serial.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  UsbPort _port;
  String _status = "Idle";
  List<Widget> _ports = [];
  List<Widget> _serialData = [];
  StreamSubscription<String> _subscription;
  Transaction<String> _transaction;
  int _deviceId;
  TextEditingController _wifiSSIDtextController = TextEditingController();
  TextEditingController _wifiPWtextController = TextEditingController();

  Future<bool> _connectTo(device) async {
    _serialData.clear();

    if (_subscription != null) {
      _subscription.cancel();
      _subscription = null;
    }

    if (_transaction != null) {
      _transaction.dispose();
      _transaction = null;
    }

    if (_port != null) {
      _port.close();
      _port = null;
    }

    if (device == null) {
      _deviceId = null;
      setState(() {
        _status = "Disconnected";
      });
      return true;
    }

    _port = await device.create();
    if (!await _port.open()) {
      setState(() {
        _status = "Failed to open port";
      });
      return false;
    }

    _deviceId = device.deviceId;
    await _port.setDTR(true);
    await _port.setRTS(true);
    await _port.setPortParameters(
        115200, UsbPort.DATABITS_8, UsbPort.STOPBITS_1, UsbPort.PARITY_NONE);

    _transaction = Transaction.stringTerminated(
        _port.inputStream, Uint8List.fromList([13, 10]));

    _subscription = _transaction.stream.listen((String line) {
      setState(() {
        _serialData.add(Text(line));
        if (_serialData.length > 20) {
          _serialData.removeAt(0);
        }
      });
    });

    setState(() {
      _status = "Connected";
    });
    return true;
  }

  void _getPorts() async {
    _ports = [];
    List<UsbDevice> devices = await UsbSerial.listDevices();
    print(devices);

    devices.forEach((device) {
      _ports.add(ListTile(
          leading: Icon(Icons.usb),
          title: Text(device.productName),
          subtitle: Text(device.manufacturerName),
          trailing: RaisedButton(
            child:
                Text(_deviceId == device.deviceId ? "Disconnect" : "Connect"),
            onPressed: () {
              _connectTo(_deviceId == device.deviceId ? null : device)
                  .then((res) {
                _getPorts();
              });
            },
          )));
    });

    setState(() {
      print(_ports);
    });
  }

  @override
  void initState() {
    super.initState();

    UsbSerial.usbEventStream.listen((UsbEvent event) {
      _getPorts();
    });

    _getPorts();
  }

  @override
  void dispose() {
    super.dispose();
    _connectTo(null);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
            appBar: AppBar(
              title: const Text('Update WIFI credentials VIA USB'),
            ),
            body: SafeArea(
                child: ListView(
              children: <Widget>[
                Center(
                    child: Column(children: <Widget>[
                  Text(
                      _ports.length > 0
                          ? "Available Serial Ports"
                          : "No serial devices available",
                      style: Theme.of(context).textTheme.title),
                  ..._ports,
                  Text('Status: $_status\n'),
                  ListTile(
                    title: TextField(
                      controller: _wifiSSIDtextController,
                      decoration: InputDecoration(
                        border: OutlineInputBorder(),
                        labelText: 'WIFI SSID',
                      ),
                    ),
                  ),
                  ListTile(
                    title: TextField(
                      controller: _wifiPWtextController,
                      decoration: InputDecoration(
                        border: OutlineInputBorder(),
                        labelText: 'WIFI Password',
                      ),
                    ),
                  ),
                  RaisedButton(
                    child: Text("Send"),
                    onPressed: _port == null
                        ? null
                        : () async {
                            if (_port == null) {
                              return;
                            }
                            String data = _wifiSSIDtextController.text +
                                "," +
                                _wifiPWtextController.text;
                            await _port
                                .write(Uint8List.fromList(data.codeUnits));
                            _wifiSSIDtextController.text = "";
                            _wifiPWtextController.text = "";
                          },
                  ),
                  Text("Result Data", style: Theme.of(context).textTheme.title),
                  ..._serialData.reversed.toList(),
                ])),
              ],
            ))));
  }
}
